package vip.liux.backend.application.serviceImpl.point;

import jakarta.persistence.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.liux.backend.application.service.point.PointsDetailService;
import vip.liux.backend.infrastructure.jpa.point.JpaPointsDetailRepository;
import vip.liux.contracts.models.point.PointsAccountDomainService;
import vip.liux.contracts.models.point.PointsUsage;
import vip.liux.contracts.repositories.point.IPointsUsageRepository;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class PointsDetailServiceImpl implements PointsDetailService {

    private final JpaPointsDetailRepository pointsDetailRepo;
    private final PointsAccountDomainService pointsAccountDomainService;

    // 积分使用记录仓储
    private final IPointsUsageRepository usageRepository;

    public PointsDetailServiceImpl(JpaPointsDetailRepository pointsDetailRepo, PointsAccountDomainService pointsAccountDomainService, IPointsUsageRepository usageRepository) {
        this.pointsDetailRepo = pointsDetailRepo;
        this.pointsAccountDomainService = pointsAccountDomainService;
        this.usageRepository = usageRepository;
    }

    /**
     * 定时扫描并处理过期积分
     */
    @Override
    @Transactional
    public void scanExpiredPoints() {
        Logger log = LoggerFactory.getLogger(PointsDetailServiceImpl.class);

        List<Tuple> expiredDetails = pointsDetailRepo.findExpiredPoints(LocalDateTime.now());
        if (expiredDetails.isEmpty()) {
            log.info("未发现需要处理的过期积分明细。");
            return;
        }
        log.info("发现 {} 条过期积分明细，开始处理。", expiredDetails.size());

        Map<Long, BigDecimal> userUsedPoints = expiredDetails.stream()
                .collect(Collectors.groupingBy(
                        t -> t.get("userId", Long.class),
                        Collectors.mapping(
                                t -> t.get("remainPoints", BigDecimal.class),
                                Collectors.reducing(BigDecimal.ZERO, BigDecimal::add)
                        )
                ));

        List<PointsUsage> usedList = expiredDetails.stream()
                .map(tuple -> {
                    BigDecimal remain = tuple.get("remainPoints", BigDecimal.class);
                    if (remain.compareTo(BigDecimal.ZERO) <= 0) {
                        return null;
                    }
                    PointsUsage usage = new PointsUsage();
                    usage.setDetailId(tuple.get("id", Long.class));
                    usage.setUsedPoints(remain);
                    usage.setOrderNo("EXPIRED_" + usage.getDetailId());
                    return usage;
                })
                .filter(Objects::nonNull)
                .toList();

        if (!usedList.isEmpty()) {
            usageRepository.saveAll(usedList);
            log.info("已生成并保存 {} 条过期积分使用记录。", usedList.size());
        } else {
            log.info("无可用剩余积分需要生成使用记录。");
        }

        userUsedPoints.forEach((userId, totalUsedPoints) -> {
            if (totalUsedPoints.compareTo(BigDecimal.ZERO) > 0) {
                pointsAccountDomainService.addAvailablePoints(userId, totalUsedPoints.negate());
                log.info("用户 {} 扣减过期积分 {}。", userId, totalUsedPoints);
            }
        });

        log.info("过期积分处理完成。");
    }
}
